Passed
Push — main ( 5f323c...70e5cf )
by LCS
03:21
created

sorter.js ➔ enableUI   B

Complexity

Conditions 7

Size

Total Lines 32
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 21
dl 0
loc 32
rs 7.9759
c 0
b 0
f 0
cc 7
1
/* eslint-disable */
2
var addSorting = (function() {
3
    'use strict';
4
    var cols,
5
        currentSort = {
6
            index: 0,
7
            desc: false
8
        };
9
10
    // returns the summary table element
11
    function getTable() {
12
        return document.querySelector('.coverage-summary');
13
    }
14
    // returns the thead element of the summary table
15
    function getTableHeader() {
16
        return getTable().querySelector('thead tr');
17
    }
18
    // returns the tbody element of the summary table
19
    function getTableBody() {
20
        return getTable().querySelector('tbody');
21
    }
22
    // returns the th element for nth column
23
    function getNthColumn(n) {
24
        return getTableHeader().querySelectorAll('th')[n];
25
    }
26
27
    function onFilterInput() {
28
        const searchValue = document.getElementById('fileSearch').value;
29
        const rows = document.getElementsByTagName('tbody')[0].children;
30
31
        // Try to create a RegExp from the searchValue. If it fails (invalid regex),
32
        // it will be treated as a plain text search
33
        let searchRegex;
34
        try {
35
            searchRegex = new RegExp(searchValue, 'i'); // 'i' for case-insensitive
36
        } catch (error) {
37
            searchRegex = null;
38
        }
39
40
        for (let i = 0; i < rows.length; i++) {
41
            const row = rows[i];
42
            let isMatch = false;
0 ignored issues
show
Unused Code introduced by
The assignment to variable isMatch seems to be never used. Consider removing it.
Loading history...
43
44
            if (searchRegex) {
45
                // If a valid regex was created, use it for matching
46
                isMatch = searchRegex.test(row.textContent);
47
            } else {
48
                // Otherwise, fall back to the original plain text search
49
                isMatch = row.textContent
50
                    .toLowerCase()
51
                    .includes(searchValue.toLowerCase());
52
            }
53
54
            row.style.display = isMatch ? '' : 'none';
55
        }
56
    }
57
58
    // loads the search box
59
    function addSearchBox() {
60
        var template = document.getElementById('filterTemplate');
61
        var templateClone = template.content.cloneNode(true);
62
        templateClone.getElementById('fileSearch').oninput = onFilterInput;
63
        template.parentElement.appendChild(templateClone);
64
    }
65
66
    // loads all columns
67
    function loadColumns() {
68
        var colNodes = getTableHeader().querySelectorAll('th'),
69
            colNode,
70
            cols = [],
71
            col,
72
            i;
73
74
        for (i = 0; i < colNodes.length; i += 1) {
75
            colNode = colNodes[i];
76
            col = {
77
                key: colNode.getAttribute('data-col'),
78
                sortable: !colNode.getAttribute('data-nosort'),
79
                type: colNode.getAttribute('data-type') || 'string'
80
            };
81
            cols.push(col);
82
            if (col.sortable) {
83
                col.defaultDescSort = col.type === 'number';
84
                colNode.innerHTML =
85
                    colNode.innerHTML + '<span class="sorter"></span>';
86
            }
87
        }
88
        return cols;
89
    }
90
    // attaches a data attribute to every tr element with an object
91
    // of data values keyed by column name
92
    function loadRowData(tableRow) {
93
        var tableCols = tableRow.querySelectorAll('td'),
94
            colNode,
95
            col,
96
            data = {},
97
            i,
98
            val;
99
        for (i = 0; i < tableCols.length; i += 1) {
100
            colNode = tableCols[i];
101
            col = cols[i];
102
            val = colNode.getAttribute('data-value');
103
            if (col.type === 'number') {
104
                val = Number(val);
105
            }
106
            data[col.key] = val;
107
        }
108
        return data;
109
    }
110
    // loads all row data
111
    function loadData() {
112
        var rows = getTableBody().querySelectorAll('tr'),
113
            i;
114
115
        for (i = 0; i < rows.length; i += 1) {
116
            rows[i].data = loadRowData(rows[i]);
117
        }
118
    }
119
    // sorts the table using the data for the ith column
120
    function sortByIndex(index, desc) {
121
        var key = cols[index].key,
122
            sorter = function(a, b) {
123
                a = a.data[key];
124
                b = b.data[key];
125
                return a < b ? -1 : a > b ? 1 : 0;
126
            },
127
            finalSorter = sorter,
128
            tableBody = document.querySelector('.coverage-summary tbody'),
129
            rowNodes = tableBody.querySelectorAll('tr'),
130
            rows = [],
131
            i;
132
133
        if (desc) {
134
            finalSorter = function(a, b) {
135
                return -1 * sorter(a, b);
136
            };
137
        }
138
139
        for (i = 0; i < rowNodes.length; i += 1) {
140
            rows.push(rowNodes[i]);
141
            tableBody.removeChild(rowNodes[i]);
142
        }
143
144
        rows.sort(finalSorter);
145
146
        for (i = 0; i < rows.length; i += 1) {
147
            tableBody.appendChild(rows[i]);
148
        }
149
    }
150
    // removes sort indicators for current column being sorted
151
    function removeSortIndicators() {
152
        var col = getNthColumn(currentSort.index),
153
            cls = col.className;
154
155
        cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, '');
156
        col.className = cls;
157
    }
158
    // adds sort indicators for current column being sorted
159
    function addSortIndicators() {
160
        getNthColumn(currentSort.index).className += currentSort.desc
161
            ? ' sorted-desc'
162
            : ' sorted';
163
    }
164
    // adds event listeners for all sorter widgets
165
    function enableUI() {
166
        var i,
167
            el,
168
            ithSorter = function ithSorter(i) {
169
                var col = cols[i];
170
171
                return function() {
172
                    var desc = col.defaultDescSort;
173
174
                    if (currentSort.index === i) {
175
                        desc = !currentSort.desc;
176
                    }
177
                    sortByIndex(i, desc);
178
                    removeSortIndicators();
179
                    currentSort.index = i;
180
                    currentSort.desc = desc;
181
                    addSortIndicators();
182
                };
183
            };
184
        for (i = 0; i < cols.length; i += 1) {
185
            if (cols[i].sortable) {
186
                // add the click event handler on the th so users
187
                // dont have to click on those tiny arrows
188
                el = getNthColumn(i).querySelector('.sorter').parentElement;
189
                if (el.addEventListener) {
190
                    el.addEventListener('click', ithSorter(i));
191
                } else {
192
                    el.attachEvent('onclick', ithSorter(i));
193
                }
194
            }
195
        }
196
    }
197
    // adds sorting functionality to the UI
198
    return function() {
199
        if (!getTable()) {
200
            return;
201
        }
202
        cols = loadColumns();
203
        loadData();
204
        addSearchBox();
205
        addSortIndicators();
206
        enableUI();
207
    };
208
})();
209
210
window.addEventListener('load', addSorting);
211